/***
 * @Author: 码上talk|RC
 * @Date: 2020-06-09 23:20:41
 * @LastEditTime: 2020-12-16 12:03:30
 * @LastEditors: 码上talk|RC
 * @Description: 
 * @FilePath: /tacomall-springboot/tacomall-api/tacomall-api-portal/src/main/java/store/tacomall/apiportal/service/impl/OrderServiceImpl.java
 * @Just do what I think it is right
 */
package store.tacomall.apiportal.service.impl;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;

import cn.hutool.core.util.ObjectUtil;

import org.springframework.transaction.TransactionDefinition;
import org.springframework.jdbc.datasource.DataSourceTransactionManager;

import store.tacomall.common.util.ExceptionUtil;
import store.tacomall.common.util.RequestUtil;
import store.tacomall.common.vo.ResponseVo;
import store.tacomall.entity.cart.Cart;
import store.tacomall.entity.goods.GoodsItem;
import store.tacomall.entity.order.Order;
import store.tacomall.entity.order.OrderMappingGoodsItem;
import store.tacomall.entity.seckill.SeckillGoodsItemApply;
import store.tacomall.mapper.goods.GoodsItemMapper;
import store.tacomall.mapper.seckill.SeckillGoodsItemApplyMapper;
import store.tacomall.mapper.order.OrderMapper;
import store.tacomall.mapper.order.OrderMappingGoodsItemMapper;
import store.tacomall.mapper.cart.CartMapper;
import store.tacomall.apiportal.service.OrderService;

@Service
public class OrderServiceImpl extends ServiceImpl<OrderMapper, Order> implements OrderService {

    final static int QUANTIRY_BUY_ONE = 1;

    @Autowired
    private CartMapper cartMapper;

    @Autowired
    private GoodsItemMapper goodsItemMapper;

    @Autowired
    private SeckillGoodsItemApplyMapper seckillGoodsItemApplyMapper;

    @Autowired
    private OrderMappingGoodsItemMapper orderMappingGoodsItemMapper;

    @Autowired
    TransactionDefinition transactionDefinition;

    @Autowired
    DataSourceTransactionManager dataSourceTransactionManager;

    /***
     * @description: 添加用户订单
     * @param {type}
     * @return:
     */
    @Override
    public ResponseVo<Order> addOrder(String fromType, JSONObject json) {
        ResponseVo<Order> responseVo = new ResponseVo<>();
        List<Map<String, Object>> buys = new ArrayList<>();
        switch (fromType) {
            case "CART":
                List<Cart> cart = cartMapper.getCarts(new QueryWrapper<Cart>().lambda()
                        .eq(Cart::getMemberId, RequestUtil.getLoginUser().getInteger("id"))
                        .in(Cart::getId, Arrays.asList(json.getString("ids").split(","))));
                for (int i = 0; i < cart.size(); i++) {
                    Map<String, Object> cartBuy = new HashMap<>();
                    Cart currentCart = cart.get(i);
                    GoodsItem currentGoodsItem = currentCart.getGoodsItem();
                    cartBuy.put("quantity", currentCart.getQuantity());
                    cartBuy.put("goodsItem", currentGoodsItem);
                    buys.add(cartBuy);
                }
                break;
            case "GOODS_ITEM":
                Map<String, Object> goodsItemBuy = new HashMap<>();
                goodsItemBuy.put("quantity", json.getInteger("quantity"));
                goodsItemBuy.put("goodsItem", goodsItemMapper
                        .selectOne(new QueryWrapper<GoodsItem>().lambda().eq(GoodsItem::getId, json.getInteger("id"))));
                buys.add(goodsItemBuy);
                break;
            case "SECKILL":
                Map<String, Object> seckillBuy = new HashMap<>();
                seckillBuy.put("quantity", QUANTIRY_BUY_ONE);
                seckillBuy
                        .put("goodsItem",
                                seckillGoodsItemApplyMapper
                                        .getSeckillGoodsItemApply(new QueryWrapper<SeckillGoodsItemApply>().lambda()
                                                .eq(SeckillGoodsItemApply::getId, json.getInteger("id")))
                                        .getGoodsItem());
                buys.add(seckillBuy);
                break;
            default:
                ExceptionUtil.throwClientException("非法参数：fromType");
        }
        TransactionStatus transactionStatus = dataSourceTransactionManager.getTransaction(transactionDefinition);
        try {
            Order order = new Order();
            List<OrderMappingGoodsItem> orderMappingGoodsItems = new ArrayList<>();
            int memberId = RequestUtil.getLoginUser().getIntValue("id");
            BigDecimal total = BigDecimal.ZERO;
            for (int i = 0; i < buys.size(); i++) {
                int quantity = (int) buys.get(i).get("quantity");
                GoodsItem goodsItem = (GoodsItem) buys.get(i).get("goodsItem");
                if (goodsItemMapper.minus(goodsItem.getId(), quantity) < 1) {
                    ExceptionUtil.throwBizException("库存不足");
                }
                OrderMappingGoodsItem orderMappingGoodsItem = new OrderMappingGoodsItem();
                total = total.add(goodsItem.getAmount().multiply(new BigDecimal(quantity)));
                orderMappingGoodsItem.setGoodsItemId(goodsItem.getId());
                orderMappingGoodsItem.setAmount(goodsItem.getAmount());
                orderMappingGoodsItem.setQuantity(quantity);
                orderMappingGoodsItems.add(orderMappingGoodsItem);
            }
            order.setMemberId(memberId);
            order.setTotalAmount(total.setScale(2, BigDecimal.ROUND_HALF_UP));
            this.baseMapper.insert(order);

            for (int i = 0; i < orderMappingGoodsItems.size(); i++) {
                OrderMappingGoodsItem orderMappingGoodsItem = orderMappingGoodsItems.get(i);
                orderMappingGoodsItem.setOrderId(order.getId());
                orderMappingGoodsItemMapper.insert(orderMappingGoodsItem);
            }

            if (fromType.equals("CART")) {
                cartMapper.delete(new QueryWrapper<Cart>().lambda().eq(Cart::getMemberId, memberId).in(Cart::getId,
                        Arrays.asList(json.getString("ids").split(","))));
            }

            dataSourceTransactionManager.commit(transactionStatus);
            responseVo.setData(order);
        } catch (Exception e) {
            dataSourceTransactionManager.rollback(transactionStatus);
            ExceptionUtil.throwSqlException(e.toString());
        }
        return responseVo;
    }

    /***
     * @description: 获取用户订单详情
     * @param {type}
     * @return:
     */
    @Override
    public ResponseVo<Order> getOrder(JSONObject json) {
        ResponseVo<Order> responseVo = new ResponseVo<>();
        LambdaQueryWrapper<Order> q = new QueryWrapper<Order>().lambda();
        q.eq(Order::getMemberId, RequestUtil.getLoginUser().getInteger("id"));
        if (ObjectUtil.isNotEmpty(json.getString("id"))) {
            q.eq(Order::getId, json.getInteger("id"));
        }
        q.eq(Order::getIsDelete, 0);
        responseVo.setData(this.baseMapper.getOrder(q));
        return responseVo;
    }

    /***
     * @description: 获取用户订单
     * @param {type}
     * @return:
     */
    @Override
    public ResponseVo<List<Order>> getOrderPage(int pageIndex, int pageSize, JSONObject json) {
        ResponseVo<List<Order>> responseVo = new ResponseVo<>();
        Page<Order> page = new Page<>(pageIndex, pageSize);
        LambdaQueryWrapper<Order> q = new QueryWrapper<Order>().lambda();
        q.eq(Order::getMemberId, RequestUtil.getLoginUser().getInteger("id"));
        if (ObjectUtil.isNotEmpty(json.getInteger("status")) && json.getInteger("status") != -1) {
            q.eq(Order::getStatus, json.getInteger("status"));
        }
        q.eq(Order::getIsDelete, 0);
        IPage<Order> result = this.baseMapper.getOrderPage(page, q);
        responseVo.setData(result.getRecords());
        return responseVo;
    }

}
